package com.smasher.component.activity

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.util.Log
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import com.liulishuo.okdownload.DownloadTask
import com.liulishuo.okdownload.SpeedCalculator
import com.liulishuo.okdownload.StatusUtil
import com.liulishuo.okdownload.StatusUtil.Status
import com.liulishuo.okdownload.core.breakpoint.BlockInfo
import com.liulishuo.okdownload.core.breakpoint.BreakpointInfo
import com.liulishuo.okdownload.core.cause.EndCause
import com.liulishuo.okdownload.core.listener.DownloadListener4WithSpeed
import com.liulishuo.okdownload.core.listener.assist.Listener4SpeedAssistExtend
import com.smasher.component.R
import com.smasher.component.databinding.ActivityUpdateVersionBinding
import com.smasher.component.util.ProgressUtil
import com.smasher.core.utils.TouchUtil
import com.smasher.update.UpdateHelper
import com.smasher.widget.base.BaseBindingActivity
import java.io.File
import java.math.BigDecimal
import java.math.RoundingMode
import java.util.concurrent.Executors

class UpdateVersionActivity : BaseBindingActivity<ActivityUpdateVersionBinding>(),
    View.OnClickListener {

    private var scheduler = Executors.newScheduledThreadPool(5)
    private val helper by lazy {
        UpdateHelper(this, "9", 50)
    }

    override fun initView() {
        mBinding.target.setOnClickListener(this)
        mBinding.buttonDownload1.setOnClickListener(this)
        mBinding.buttonDownload2.setOnClickListener(this)
        mBinding.buttonUpdate1.setOnClickListener(this)
        mBinding.buttonUpdate2.setOnClickListener(this)
        permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
    }

    override fun initData() {}

    override fun onClick(v: View) {
        if (TouchUtil.isFastTouch()) {
            return
        }
        when (v.id) {
            R.id.target -> {
            }

            R.id.button_update1 -> {
                helper.checkVersion(this)
            }

            R.id.button_update2 -> {
//                helper.checkVersionOnly(this, silent = true) {
//                    Log.d(TAG, "onClick: $it")
//                }
                helper.checkVersion(this, silent = false, force = false)
            }

            R.id.button_download1 -> {
                val task = createTask()
                task.enqueue(downloadListener)
            }

            R.id.button_download2 -> {

            }
        }
    }

    private fun createUrl(): String {
        return TEST_URL
    }

    private fun createTask(): DownloadTask {
        return createTask(createUrl())
    }

    private fun createTask(url: String): DownloadTask {
        val filename = "each-block-progress-test.apk"
        val parentFile: File = getParentFile(this)
        val target = File(parentFile, filename)
        if (target.exists()) {
            target.delete()
        }
        return DownloadTask.Builder(url, parentFile)
            .setFilename(filename) // the minimal interval millisecond for callback progress
            .setConnectionCount(6)
            .setMinIntervalMillisCallbackProcess(16) // ignore the same task has already completed in the past.
            .setPassIfAlreadyCompleted(false)
            .build()
    }


    private fun initStatus(task: DownloadTask) {
        val status = StatusUtil.getStatus(task)
        Log.i(TAG, "initStatus: status=$status")
        val info = StatusUtil.getCurrentInfo(task)
        // blocks
        if (info != null) {
            val blockCount = info.blockCount
            for (blockIndex in 0 until blockCount) {
                val blockInfo = info.getBlock(blockIndex)
                Log.i(
                    TAG,
                    "block $blockIndex: start=${blockInfo.rangeLeft} end=${blockInfo.rangeRight} "
                )
            }
        }
    }

    private fun getParentFile(context: Context): File {
        val externalSaveDir = context.externalCacheDir
        return externalSaveDir ?: context.cacheDir
    }

    private val downloadListener = object : DownloadListener4WithSpeed() {
        override fun taskStart(task: DownloadTask) {
            Log.i(TAG, "taskStart: ")
        }

        override fun connectStart(
            task: DownloadTask,
            blockIndex: Int,
            requestHeaderFields: MutableMap<String, MutableList<String>>
        ) {
            Log.i(TAG, "connectStart: ")
        }

        override fun connectEnd(
            task: DownloadTask,
            blockIndex: Int,
            responseCode: Int,
            responseHeaderFields: MutableMap<String, MutableList<String>>
        ) {
            Log.i(TAG, "connectEnd: ")
        }

        @SuppressLint("SetTextI18n")
        override fun taskEnd(
            task: DownloadTask,
            cause: EndCause,
            realCause: Exception?,
            taskSpeed: SpeedCalculator
        ) {
            Log.i(TAG, "taskEnd: cause=$cause realCause=$realCause")

            val breakpoint = task.info
            val offset = breakpoint?.totalOffset ?: 0L
            val total = breakpoint?.totalLength ?: 0L
            Log.i(
                TAG,
                "taskEnd: currentOffset=${offset} total=${total} speed=${taskSpeed.speed()}"
            )
            when (StatusUtil.getStatus(task)) {
                Status.PENDING -> {
                    mBinding.name.text = "${task.filename}(等待中)"
                    mBinding.speed.text = ""
                }

                Status.RUNNING -> {
                    mBinding.name.text = "${task.filename}(下载中)"
                    mBinding.speed.text = ""
                }

                Status.COMPLETED -> {
                    mBinding.name.text = "${task.filename}(100%)"
                    mBinding.speed.text = taskSpeed.speed()
                }

                Status.IDLE -> {
                    mBinding.name.text = "${task.filename}"
                    mBinding.speed.text = ""
                }

                Status.UNKNOWN -> {
                    mBinding.name.text = "${task.filename}(未知)"
                    mBinding.speed.text = ""
                }

                else -> {
                    mBinding.name.text = "${task.filename}(未知)"
                    mBinding.speed.text = ""
                }
            }

        }

        override fun infoReady(
            task: DownloadTask,
            info: BreakpointInfo,
            fromBreakpoint: Boolean,
            model: Listener4SpeedAssistExtend.Listener4SpeedModel
        ) {
            // task
            ProgressUtil.calcProgressToViewAndMark(
                mBinding.progressBar,
                info.totalOffset, info.totalLength
            )

            mBinding.name.text = task.filename

            val status = StatusUtil.getStatus(task)
            Log.i(TAG, "infoReady: status=$status")
            val breakInfo = StatusUtil.getCurrentInfo(task)
            // blocks
            if (breakInfo != null) {
                Log.i(TAG, "infoReady: total length=${breakInfo.totalLength}")
                val blockCount = breakInfo.blockCount
                for (blockIndex in 0 until blockCount) {
                    val blockInfo = breakInfo.getBlock(blockIndex)
                    Log.i(
                        TAG,
                        "block $blockIndex: start=${blockInfo.rangeLeft} end=${blockInfo.rangeRight} "
                    )
                }
            }
        }

        override fun progressBlock(
            task: DownloadTask,
            blockIndex: Int,
            currentBlockOffset: Long,
            blockSpeed: SpeedCalculator
        ) {
            Log.i(TAG, "progressBlock: speed=${blockSpeed.speed()}")
        }

        @SuppressLint("SetTextI18n")
        override fun progress(task: DownloadTask, currentOffset: Long, taskSpeed: SpeedCalculator) {

            ProgressUtil.updateProgressToViewWithMark(mBinding.progressBar, currentOffset)

            val breakpoint = task.info
            val total = breakpoint?.totalLength ?: 0L
            Log.i(
                TAG,
                "progress: currentOffset=${currentOffset} total=${total} speed=${taskSpeed.speed()}"
            )
            if (total != 0L) {
                val progressDecimal = BigDecimal(currentOffset.toString())
                val totalDecimal = BigDecimal(total.toString())
                val percentCalculate =
                    progressDecimal.divide(totalDecimal, 2, RoundingMode.HALF_UP)
                        .multiply(BigDecimal("100"))
                val percent = percentCalculate.toInt()
                Log.i(TAG, "progress: $percent%")
                mBinding.name.text = "${task.filename}($percent%)"
                mBinding.speed.text = taskSpeed.speed()
            }
        }

        override fun blockEnd(
            task: DownloadTask,
            blockIndex: Int,
            info: BlockInfo?,
            blockSpeed: SpeedCalculator
        ) {
            Log.i(TAG, "blockEnd: ")
        }
    }


    private fun installApk(context: Context, uri: Uri) {
        val typeApk = "application/vnd.android.package-archive"
        val intent = Intent(Intent.ACTION_VIEW)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        intent.setDataAndType(uri, typeApk)
        if (Build.VERSION.SDK_INT >= 24) { //版本是否在7.0以上
//            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            intent.addFlags(
                Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
            )
            intent.addCategory("android.intent.category.DEFAULT")
            //对目标apk的uri临时授权 使得有权限打开该Uri指向的Apk
        } else {
            intent.addCategory("android.intent.category.DEFAULT")
        }
        context.startActivity(intent)
    }

    override fun onDestroy() {
        super.onDestroy()
        scheduler.shutdown()
        helper.release(this)
    }


    private val permissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) {
            if (it) {
                Log.i(TAG, "onCreate: permission granted")
            } else {
                Log.i(TAG, "onCreate: permission denied")
            }
        }


    companion object {
        const val TAG = "Target1"

        private const val TEST_URL =
            "https://cdn.llscdn.com/yy/files/xs8qmxn8-lls-LLS-5.8-800-20171207-111607.apk"
    }

}